About
Faraday synth is a four voice, two octave chromatic synthesizer. Synthesis is carried out by a miniature arduino board that feeds a one watt amplifier and two inch speaker. There are four buttons that play notes, four knobs that control pitch, a latch button, a volume knob, and a power button. The enclosure is machined cast aluminum with a hand etched circuit board.
The synthesis algorithm is quite simple in order to run on the arduino, and consists of four one-bit oscillators that are updated by an interrupt service routine running at 50 kHz. Each oscillator's frequency is determined by counting the number of interrupts (i.e. samples) per half wave cycle, then toggling the oscillator's waveform state high or low. Interaction is handled within the main program loop where button states are read, potentiometer values are read and low pass filtered, and state variables are set.
Faraday synth was built as a present for my son on his third birthday.
Photos
Circuitry
Code
//------------------------------------------------------------------------------
// Faraday Synthesizer
//
// Interrupt driven 1-bit four-voice synthesis for arduino + atmega328 @ 16MHz
// Written for Faraday Moses Lin-Baker's 3rd Birthday (01/08/14)
//
// I Love You Faraday!
//
// Cooper Baker - 11/29/13
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include "main.h"
// Definitions
//------------------------------------------------------------------------------
//2MHz for /8 prescale from 16MHz
#define TIMER_FREQ 2000000.0
// digital pins
#define SPEAKER_PIN 2
// led pins
#define LED_1_PIN 3
#define LED_2_PIN 4
#define LED_3_PIN 5
#define LED_4_PIN 6
#define LED_5_PIN 7
// switch pins
#define SW_1_PIN 8
#define SW_2_PIN 9
#define SW_3_PIN 10
#define SW_4_PIN 11
#define SW_5_PIN 12
// analog pins
#define POT_1_PIN 3
#define POT_2_PIN 2
#define POT_3_PIN 1
#define POT_4_PIN 0
// isr clock rate ( i.e. sample rate )
#define SAMPLE_RATE 50000
// clipping macro
#define clip( x, l, h ) (x) < (l) ? (l) : ( (x) > (h) ? (h) : (x) )
//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------
// half-cycle-samples lookup table
// half-cycle-samples = ( sample-rate / cycles-per-second ) / 2.0
// 55Hz to 440Hz
int freqArray[ 1024 ] = { 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57 };
// potentiometer values
int pot1 = 0;
int pot2 = 0;
int pot3 = 0;
int pot4 = 0;
// oscillator states
byte osc1 = 0;
byte osc2 = 0;
byte osc3 = 0;
byte osc4 = 0;
// gated oscillator states
byte out1 = 0;
byte out2 = 0;
byte out3 = 0;
byte out4 = 0;
// switch states
byte sw1 = 0;
byte sw2 = 0;
byte sw3 = 0;
byte sw4 = 0;
byte sw5 = 0;
// switch states history
byte sw1Prev = 0;
byte sw2Prev = 0;
byte sw3Prev = 0;
byte sw4Prev = 0;
byte sw5Prev = 0;
// gate/latch states
byte gate1 = 0;
byte gate2 = 0;
byte gate3 = 0;
byte gate4 = 0;
byte latch = 0;
// mixed gated oscillators
byte outMix = 0;
// oscillator half-cycle counters
int inc1 = 0;
int inc2 = 0;
int inc3 = 0;
int inc4 = 0;
// output byte for PORTD register
byte output;
// interrupt timer variables
unsigned char clock_cycles = 0;
unsigned int isr_latency = 0;
//------------------------------------------------------------------------------
// Prototypes
//------------------------------------------------------------------------------
void setup( void );
void loop( void );
void setup_timer_2( float clock_frequency );
void hello( void );
//------------------------------------------------------------------------------
// ISR - interrupt service routine for TIMER2_OVF_vect ( timer 2 overflow )
// updates, gates, mixes, and outputs oscillator signals
//------------------------------------------------------------------------------
ISR( TIMER2_OVF_vect )
{
// gate and mix oscillators into output byte
output = ( osc1 & gate1 ) || ( osc2 & gate2 ) || ( osc3 & gate3 ) || ( osc4 & gate4 );
// shift output signal to speaker pin and bitmask into PORTD register
PORTD = PIND | ( output << SPEAKER_PIN );
// half-cycle counter wrapping
if( ++inc1 >= freqArray[ pot1 ] )
{
osc1 = !osc1;
inc1 = 0;
}
else
{
osc1 = osc1;
inc1 = inc1;
}
if( ++inc2 >= freqArray[ pot2 ] )
{
osc2 = !osc2;
inc2 = 0;
}
else
{
osc2 = osc2;
inc2 = inc2;
}
if( ++inc3 >= freqArray[ pot3 ] )
{
osc3 = !osc3;
inc3 = 0;
}
else
{
osc3 = osc3;
inc3 = inc3;
}
if( ++inc4 >= freqArray[ pot4 ] )
{
osc4 = !osc4;
inc4 = 0;
}
else
{
osc4 = osc4;
inc4 = inc4;
}
// store current timer value for latency correction
isr_latency = TCNT2;
// reload the timer and correct for latency
TCNT2 = isr_latency + clock_cycles;
}
//------------------------------------------------------------------------------
// setup_timer_2 - sets up frequency of timer 2 overflow
//------------------------------------------------------------------------------
void setup_timer_2( float clock_frequency )
{
// calculate overflow count value
clock_cycles = (int)( ( 257.0 - ( (float)TIMER_FREQ / clock_frequency ) ) + 0.5 );
// timer 2 settings: timer prescaler /8,
TCCR2A = 0;
TCCR2B = 0 << CS22 | 1 << CS21 | 0 << CS20;
// timer 2 overflow interrupt enable
TIMSK2 = 1 << TOIE2;
// timer 2 overflow count
TCNT2 = clock_cycles;
}
//------------------------------------------------------------------------------
// hello - flashes lights and plays a note
//------------------------------------------------------------------------------
void hello( void )
{
// select and turn on a note
pot1 = 960;
gate1 = HIGH;
// turn on the lights
digitalWrite( LED_1_PIN, HIGH );
digitalWrite( LED_2_PIN, HIGH );
digitalWrite( LED_3_PIN, HIGH );
digitalWrite( LED_4_PIN, HIGH );
digitalWrite( LED_5_PIN, HIGH );
// wait a moment
delay( 10 );
// turn off the note
gate1 = LOW;
// wait a while
delay( 90 );
// turn off the lights
digitalWrite( LED_1_PIN, LOW );
digitalWrite( LED_2_PIN, LOW );
digitalWrite( LED_3_PIN, LOW );
digitalWrite( LED_4_PIN, LOW );
digitalWrite( LED_5_PIN, LOW );
}
//------------------------------------------------------------------------------
// setup - initializes the microcontroller
//------------------------------------------------------------------------------
void setup( void )
{
// turn off the built-in led
pinMode ( 13, OUTPUT );
digitalWrite( 13, LOW );
// input pin initializations
pinMode( SW_1_PIN, INPUT_PULLUP );
pinMode( SW_2_PIN, INPUT_PULLUP );
pinMode( SW_3_PIN, INPUT_PULLUP );
pinMode( SW_4_PIN, INPUT_PULLUP );
pinMode( SW_5_PIN, INPUT_PULLUP );
// output pin initializations
pinMode( LED_1_PIN, OUTPUT );
pinMode( LED_2_PIN, OUTPUT );
pinMode( LED_3_PIN, OUTPUT );
pinMode( LED_4_PIN, OUTPUT );
pinMode( LED_5_PIN, OUTPUT );
// speaker pin initialization
pinMode( SPEAKER_PIN, INPUT_PULLUP );
// interrupt timer initialization
setup_timer_2( SAMPLE_RATE );
// say hello
hello();
}
//------------------------------------------------------------------------------
// loop - the main program loop
//------------------------------------------------------------------------------
void loop( void )
{
// read and low-pass filter the potentiometers
pot1 = ( analogRead( POT_1_PIN ) * 0.09 ) + ( pot1 * 0.91 );
pot2 = ( analogRead( POT_2_PIN ) * 0.09 ) + ( pot2 * 0.91 );
pot3 = ( analogRead( POT_3_PIN ) * 0.09 ) + ( pot3 * 0.91 );
pot4 = ( analogRead( POT_4_PIN ) * 0.09 ) + ( pot4 * 0.91 );
// clip off noise at the ends of the potentiometers' ranges
pot1 = clip( pot1, 64, 960 );
pot2 = clip( pot2, 64, 960 );
pot3 = clip( pot3, 64, 960 );
pot4 = clip( pot4, 64, 960 );
// read the switches
sw1 = ! digitalRead( SW_1_PIN );
sw2 = ! digitalRead( SW_2_PIN );
sw3 = ! digitalRead( SW_3_PIN );
sw4 = ! digitalRead( SW_4_PIN );
sw5 = ! digitalRead( SW_5_PIN );
// toggle latch when switch 5 goes high
if( ( sw5 == HIGH ) && ( sw5Prev == LOW ) )
{
latch = !latch;
}
if( latch )
{
// if latch is on toggle gates when switches go high
if( ( sw1 == HIGH ) && ( sw1Prev == LOW ) )
{
gate1 = !gate1;
}
if( ( sw2 == HIGH ) && ( sw2Prev == LOW ) )
{
gate2 = !gate2;
}
if( ( sw3 == HIGH ) && ( sw3Prev == LOW ) )
{
gate3 = !gate3;
}
if( ( sw4 == HIGH ) && ( sw4Prev == LOW ) )
{
gate4 = !gate4;
}
}
else
{
// if latch is off set gates to switch states
gate1 = sw1;
gate2 = sw2;
gate3 = sw3;
gate4 = sw4;
}
// switch history
sw1Prev = sw1;
sw2Prev = sw2;
sw3Prev = sw3;
sw4Prev = sw4;
sw5Prev = sw5;
// update leds according to gate/latch values
digitalWrite( LED_1_PIN, gate1 );
digitalWrite( LED_2_PIN, gate2 );
digitalWrite( LED_3_PIN, gate3 );
digitalWrite( LED_4_PIN, gate4 );
digitalWrite( LED_5_PIN, latch );
}
//------------------------------------------------------------------------------
// main - entry point for microcontroller config and operation
//------------------------------------------------------------------------------
int main(void)
{
init();
setup();
spin:
loop();
goto spin;
return 0;
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------
// Faraday Synthesizer
//
// Interrupt driven 1-bit four-voice synthesis for arduino + atmega328 @ 16MHz
// Written for Faraday Moses Lin-Baker's 3rd Birthday (01/08/14)
//
// I Love You Faraday!
//
// Cooper Baker - 11/29/13
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include "main.h"
// Definitions
//------------------------------------------------------------------------------
//2MHz for /8 prescale from 16MHz
#define TIMER_FREQ 2000000.0
// digital pins
#define SPEAKER_PIN 2
// led pins
#define LED_1_PIN 3
#define LED_2_PIN 4
#define LED_3_PIN 5
#define LED_4_PIN 6
#define LED_5_PIN 7
// switch pins
#define SW_1_PIN 8
#define SW_2_PIN 9
#define SW_3_PIN 10
#define SW_4_PIN 11
#define SW_5_PIN 12
// analog pins
#define POT_1_PIN 3
#define POT_2_PIN 2
#define POT_3_PIN 1
#define POT_4_PIN 0
// isr clock rate ( i.e. sample rate )
#define SAMPLE_RATE 50000
// clipping macro
#define clip( x, l, h ) (x) < (l) ? (l) : ( (x) > (h) ? (h) : (x) )
//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------
// half-cycle-samples lookup table
// half-cycle-samples = ( sample-rate / cycles-per-second ) / 2.0
// 55Hz to 440Hz
int freqArray[ 1024 ] = { 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57 };
// potentiometer values
int pot1 = 0;
int pot2 = 0;
int pot3 = 0;
int pot4 = 0;
// oscillator states
byte osc1 = 0;
byte osc2 = 0;
byte osc3 = 0;
byte osc4 = 0;
// gated oscillator states
byte out1 = 0;
byte out2 = 0;
byte out3 = 0;
byte out4 = 0;
// switch states
byte sw1 = 0;
byte sw2 = 0;
byte sw3 = 0;
byte sw4 = 0;
byte sw5 = 0;
// switch states history
byte sw1Prev = 0;
byte sw2Prev = 0;
byte sw3Prev = 0;
byte sw4Prev = 0;
byte sw5Prev = 0;
// gate/latch states
byte gate1 = 0;
byte gate2 = 0;
byte gate3 = 0;
byte gate4 = 0;
byte latch = 0;
// mixed gated oscillators
byte outMix = 0;
// oscillator half-cycle counters
int inc1 = 0;
int inc2 = 0;
int inc3 = 0;
int inc4 = 0;
// output byte for PORTD register
byte output;
// interrupt timer variables
unsigned char clock_cycles = 0;
unsigned int isr_latency = 0;
//------------------------------------------------------------------------------
// Prototypes
//------------------------------------------------------------------------------
void setup( void );
void loop( void );
void setup_timer_2( float clock_frequency );
void hello( void );
//------------------------------------------------------------------------------
// ISR - interrupt service routine for TIMER2_OVF_vect ( timer 2 overflow )
// updates, gates, mixes, and outputs oscillator signals
//------------------------------------------------------------------------------
ISR( TIMER2_OVF_vect )
{
// gate and mix oscillators into output byte
output = ( osc1 & gate1 ) || ( osc2 & gate2 ) || ( osc3 & gate3 ) || ( osc4 & gate4 );
// shift output signal to speaker pin and bitmask into PORTD register
PORTD = PIND | ( output << SPEAKER_PIN );
// half-cycle counter wrapping
if( ++inc1 >= freqArray[ pot1 ] )
{
osc1 = !osc1;
inc1 = 0;
}
else
{
osc1 = osc1;
inc1 = inc1;
}
if( ++inc2 >= freqArray[ pot2 ] )
{
osc2 = !osc2;
inc2 = 0;
}
else
{
osc2 = osc2;
inc2 = inc2;
}
if( ++inc3 >= freqArray[ pot3 ] )
{
osc3 = !osc3;
inc3 = 0;
}
else
{
osc3 = osc3;
inc3 = inc3;
}
if( ++inc4 >= freqArray[ pot4 ] )
{
osc4 = !osc4;
inc4 = 0;
}
else
{
osc4 = osc4;
inc4 = inc4;
}
// store current timer value for latency correction
isr_latency = TCNT2;
// reload the timer and correct for latency
TCNT2 = isr_latency + clock_cycles;
}
//------------------------------------------------------------------------------
// setup_timer_2 - sets up frequency of timer 2 overflow
//------------------------------------------------------------------------------
void setup_timer_2( float clock_frequency )
{
// calculate overflow count value
clock_cycles = (int)( ( 257.0 - ( (float)TIMER_FREQ / clock_frequency ) ) + 0.5 );
// timer 2 settings: timer prescaler /8,
TCCR2A = 0;
TCCR2B = 0 << CS22 | 1 << CS21 | 0 << CS20;
// timer 2 overflow interrupt enable
TIMSK2 = 1 << TOIE2;
// timer 2 overflow count
TCNT2 = clock_cycles;
}
//------------------------------------------------------------------------------
// hello - flashes lights and plays a note
//------------------------------------------------------------------------------
void hello( void )
{
// select and turn on a note
pot1 = 960;
gate1 = HIGH;
// turn on the lights
digitalWrite( LED_1_PIN, HIGH );
digitalWrite( LED_2_PIN, HIGH );
digitalWrite( LED_3_PIN, HIGH );
digitalWrite( LED_4_PIN, HIGH );
digitalWrite( LED_5_PIN, HIGH );
// wait a moment
delay( 10 );
// turn off the note
gate1 = LOW;
// wait a while
delay( 90 );
// turn off the lights
digitalWrite( LED_1_PIN, LOW );
digitalWrite( LED_2_PIN, LOW );
digitalWrite( LED_3_PIN, LOW );
digitalWrite( LED_4_PIN, LOW );
digitalWrite( LED_5_PIN, LOW );
}
//------------------------------------------------------------------------------
// setup - initializes the microcontroller
//------------------------------------------------------------------------------
void setup( void )
{
// turn off the built-in led
pinMode ( 13, OUTPUT );
digitalWrite( 13, LOW );
// input pin initializations
pinMode( SW_1_PIN, INPUT_PULLUP );
pinMode( SW_2_PIN, INPUT_PULLUP );
pinMode( SW_3_PIN, INPUT_PULLUP );
pinMode( SW_4_PIN, INPUT_PULLUP );
pinMode( SW_5_PIN, INPUT_PULLUP );
// output pin initializations
pinMode( LED_1_PIN, OUTPUT );
pinMode( LED_2_PIN, OUTPUT );
pinMode( LED_3_PIN, OUTPUT );
pinMode( LED_4_PIN, OUTPUT );
pinMode( LED_5_PIN, OUTPUT );
// speaker pin initialization
pinMode( SPEAKER_PIN, INPUT_PULLUP );
// interrupt timer initialization
setup_timer_2( SAMPLE_RATE );
// say hello
hello();
}
//------------------------------------------------------------------------------
// loop - the main program loop
//------------------------------------------------------------------------------
void loop( void )
{
// read and low-pass filter the potentiometers
pot1 = ( analogRead( POT_1_PIN ) * 0.09 ) + ( pot1 * 0.91 );
pot2 = ( analogRead( POT_2_PIN ) * 0.09 ) + ( pot2 * 0.91 );
pot3 = ( analogRead( POT_3_PIN ) * 0.09 ) + ( pot3 * 0.91 );
pot4 = ( analogRead( POT_4_PIN ) * 0.09 ) + ( pot4 * 0.91 );
// clip off noise at the ends of the potentiometers' ranges
pot1 = clip( pot1, 64, 960 );
pot2 = clip( pot2, 64, 960 );
pot3 = clip( pot3, 64, 960 );
pot4 = clip( pot4, 64, 960 );
// read the switches
sw1 = ! digitalRead( SW_1_PIN );
sw2 = ! digitalRead( SW_2_PIN );
sw3 = ! digitalRead( SW_3_PIN );
sw4 = ! digitalRead( SW_4_PIN );
sw5 = ! digitalRead( SW_5_PIN );
// toggle latch when switch 5 goes high
if( ( sw5 == HIGH ) && ( sw5Prev == LOW ) )
{
latch = !latch;
}
if( latch )
{
// if latch is on toggle gates when switches go high
if( ( sw1 == HIGH ) && ( sw1Prev == LOW ) )
{
gate1 = !gate1;
}
if( ( sw2 == HIGH ) && ( sw2Prev == LOW ) )
{
gate2 = !gate2;
}
if( ( sw3 == HIGH ) && ( sw3Prev == LOW ) )
{
gate3 = !gate3;
}
if( ( sw4 == HIGH ) && ( sw4Prev == LOW ) )
{
gate4 = !gate4;
}
}
else
{
// if latch is off set gates to switch states
gate1 = sw1;
gate2 = sw2;
gate3 = sw3;
gate4 = sw4;
}
// switch history
sw1Prev = sw1;
sw2Prev = sw2;
sw3Prev = sw3;
sw4Prev = sw4;
sw5Prev = sw5;
// update leds according to gate/latch values
digitalWrite( LED_1_PIN, gate1 );
digitalWrite( LED_2_PIN, gate2 );
digitalWrite( LED_3_PIN, gate3 );
digitalWrite( LED_4_PIN, gate4 );
digitalWrite( LED_5_PIN, latch );
}
//------------------------------------------------------------------------------
// main - entry point for microcontroller config and operation
//------------------------------------------------------------------------------
int main(void)
{
init();
setup();
spin:
loop();
goto spin;
return 0;
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------